package com.littcore.saap.core.module.exp;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.io.FilenameUtils;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.littcore.io.util.FileUtils;
import com.littcore.io.util.IOUtils;

import freemarker.cache.StringTemplateLoader;
import freemarker.ext.beans.BeansWrapper;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.ObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateHashModel;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;


/**
 * XML格式word导出.
 * 
 * <pre><b>描述：</b>
 *    根据XML格式的word模板导出word文件.
 * 将制作好的word模板（最好是2007以后版本）另存为xml格式，通过解析xml并填充，简化word模板的解析
 * 用freemarker将xml作为字符串解析，并通过模板标签处理复杂内容  
 * 
 * 注：该方式导出的文件名后缀为.xml，但是可以用word直接打开
 * </pre>
 * 
 * <pre><b>修改记录：</b>
 *    
 * </pre>
 * 
 * @author <a href="mailto:littcai@hotmail.com">蔡源</a>
 * @since 2015年2月28日
 * @version 1.0
 */
public class WordXmlExpWriter {
  
  private final static Logger logger = LoggerFactory.getLogger(ExcelExtExpWriter.class);
  
  private File targetFile;
  
  /** 数据上下文. */
  private Map<String, Object> context = new HashMap<String, Object>();  
  
  /** 需要动态插入的图片 */
  private File[] imageFiles;
  
  Configuration templateConfig = new Configuration(); 
  
  StringTemplateLoader templateLoader = new StringTemplateLoader();
  
  public WordXmlExpWriter(String targetPath, String targetFileName) throws Exception
  {
    this.targetFile = new File(targetPath, targetFileName);
    if(!targetFile.getParentFile().exists())
    {
      FileUtils.createDirectory(targetFile.getParentFile());
    }
    this.initFreemaker();    
  }
  
  /**
   * Inits the freemaker.
   * 
   * @throws TemplateException the template exception
   * @throws IOException Signals that an I/O exception has occurred.
   * @throws ConfigurationException the configuration exception
   */
  private void initFreemaker() throws TemplateException,IOException,ConfigurationException
  {
    templateConfig = new Configuration();
    templateConfig.setClassForTemplateLoading(this.getClass(), "/");
    templateConfig.setTemplateLoader(templateLoader);
    templateConfig.setClassicCompatible(true);  //允许NULL值
    //templateConfig.setDirectoryForTemplateLoading(new File(projectPath, "template"));
    BeansWrapper wrapper = (BeansWrapper)BeansWrapper.BEANS_WRAPPER;   
    wrapper.setExposureLevel(BeansWrapper.EXPOSE_ALL);
    TemplateHashModel tempStatics = wrapper.getStaticModels();
    PropertiesConfiguration config = new PropertiesConfiguration("freemarkerstatic.properties");
    Iterator keyIterator = config.getKeys();
    while(keyIterator.hasNext())
    {
      String key = keyIterator.next().toString();
      templateConfig.setSharedVariable(key, tempStatics.get(config.getString(key)));
    }   
    // 指定模版如何查看数据模型.
    templateConfig.setObjectWrapper(new DefaultObjectWrapper()); 
        
    this.context.put("static", ((BeansWrapper)templateConfig.getObjectWrapper()).getStaticModels());  
    this.context.put("thread", useClass("java.lang.Thread"));  
    this.context.put("system", useClass("java.lang.System")); 
  }
  
  //拿到静态Class的Model  
  public TemplateModel useClass(String className) throws TemplateModelException  
  {  
      BeansWrapper wrapper = (BeansWrapper) templateConfig.getObjectWrapper();  
      TemplateHashModel staticModels = wrapper.getStaticModels();  
      return staticModels.get(className);  
  }
  
  //拿到目标对象的model  
  public TemplateModel useObjectModel(Object target) throws TemplateModelException  
  {  
      ObjectWrapper wrapper = templateConfig.getObjectWrapper();  
      TemplateModel model = wrapper.wrap(target);  
      return model;         
  }  
    
  //拿到目标对象某个方法的Model    
  public TemplateModel useObjectMethod(Object target, String methodName) throws TemplateModelException  
  {     
      TemplateHashModel model = (TemplateHashModel) useObjectModel(target);  
      return model.get(methodName);         
  }  
  
  public void addData(String name, Object data)
  {
    this.context.put(name, data);
  }
  
  public void addData(Map<String, Object> data)
  {
    this.context.putAll(data);
  }
  
  public File build(File templateFile) throws IOException, InvalidFormatException
  {
    String fileName = FilenameUtils.getBaseName(templateFile.getName());
    
    return this.build(fileName, new FileInputStream(templateFile));
  }
  
  public File build(String templateName, InputStream templateInputStream) throws IOException, InvalidFormatException
  {
    StringWriter stringWriter = new StringWriter();
    IOUtils.copy(templateInputStream, stringWriter);
    String fileContent = stringWriter.toString();
    
//  XWPFDocument wordDocument = new XWPFDocument(new FileInputStream(templateFile));
//  XWPFWordExtractor extractor = new XWPFWordExtractor(wordDocument);
  
//  String fileContent = extractor.getText();
//  fileContent = wordDocument.getDocument().xmlText();
//  
//  System.out.println(fileContent);
  
    StringTemplateLoader stringTemplateLoader = (StringTemplateLoader)templateConfig.getTemplateLoader();
    stringTemplateLoader.putTemplate(templateName, fileContent);    
    
    Template template = templateConfig.getTemplate(templateName);
    template.setEncoding("UTF-8");
       
    Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(targetFile),"UTF-8"));
    try
    {
      template.process(this.context, writer);
      writer.flush();
    } 
    catch (TemplateException e)
    {
      throw new IllegalStateException("Can't process template parser.", e);
    }
    finally
    {
      IOUtils.closeQuietly(writer);
    }  
    return targetFile;
  }
      
  public static void main(String[] args) throws Exception
  {    
    //XWPFDocument wordDocument = new XWPFDocument(new FileInputStream(new File("d:\\SH-SF02-t.xml")));
    //POIXMLDocument.openPackage(new File("d:\\SH-SF02-t.xml").getPath());
    WordXmlExpWriter writer = new WordXmlExpWriter("d:\\", "SH-SF02-t.xml");    
    
    writer.addData("orderDate", new Date());
    writer.addData("totalNum", 456);
    writer.build(new File("d:\\SH-SF02.xml"));
  }
}
